// ProjectName: go-learn-demo
// PackageName: channelybxb
// Description:
// Author: hy.bai
// Date: 2025-07-30 21:33

package main

import (
	"fmt"
	"time"
)

// 定义一个全局变量，用来指定channel的长度。
var length = 10

// 写数据的协程
func writeData(intChan chan int) {
	for i := 0; i < length; i++ {
		intChan <- (i + 1) * 10
	}
	close(intChan) // 关闭Channel
}

// 读数据的协程
func readData(intChan chan int, exitChan chan bool) {
	var i int8 = 1
	for {
		// 从Channel中，读取数据，如果读取到数据ok为true，否则为false
		value, ok := <-intChan
		if !ok { // 读取不到数据返回false，之后取反是true，执行break
			break
		}
		fmt.Printf("第%d次 - 读到数据:%v\n", i, value)
		i++
		time.Sleep(100 * time.Millisecond)
	}
	// readData管道读取完数据后，即任务完成
	exitChan <- true // 把true值写入exitChan管道。
	close(exitChan)
}

/*
实现思路：

	1.创建两个Channel,分别是intChan和exitChan
	2.开启两个协程,分别是readData和writeData
	3.监听exitChan，阻塞main线程，等待writeData和readData两个协程执行完毕。
*/
func main() {
	// 1.创建两个Channel,分别是intChan和exitChan
	// 注意:由协程在一直读的情况下，写入多少元素都可以，也不会死锁。
	// 原因是：协程在读数据是出队操作,读取之后不会占用队列的容量。
	var intChan = make(chan int, length)
	var exitChan = make(chan bool, 1)

	// 2.开启两个协程,分别是readData和writeData
	go writeData(intChan)
	go readData(intChan, exitChan)

	// 3.监听exitChan，阻塞main线程，等待writeData和readData两个协程执行完毕。
	// for循环的作用是：阻塞主线程，等价于wg.Wait()
	for {
		_, ok := <-exitChan // 从Channel中，读取数据，如果读取到数据ok为true，否则为false
		// if语句的判断条件使用ok和!ok都可以，根本的原因是：exitChan是单值true。
		// 读取数据ok为true，!ok取到零值(即：bool类型的默认值也是false)，都代表读取完毕。
		if ok { // 这里也可以使用value值来判断
			break
		}
		// 判读ok时，下面不会执行，使用!ok时，下面会执行，循环会多执行一次。
		fmt.Println("任务执行完毕")
	}
	fmt.Println("main函数结束")
}
